#ifndef _FENGINE_INPUT_MANAGER
#define _FENGINE_INPUT_MANAGER

#include <vector>
#include <list>
#include "stdafx.h"
#include "KeyboardInputListener.h"
#include "MouseInputListener.h"
#include "FEngineType.h"

namespace FEngine
{
	class KeyboardInputListener;
	class MouseInputListener;

	/**
	 * Singleton.
	 * Handle the event thrown by the keyboard and the mouse.
	 * Register and manage every keyboard and mouse input listeners.
	 */
	class InputManager
	{
		public:

			static enum Keyboard
			{
				KEY_A = 1,
				KEY_B,
				KEY_C,
				KEY_D,
				KEY_E,
				KEY_F,
				KEY_G,
				KEY_H,
				KEY_I,
				KEY_J,
				KEY_K,
				KEY_L,
				KEY_M,
				KEY_N,
				KEY_O,
				KEY_P,
				KEY_Q,
				KEY_R,
				KEY_S,
				KEY_T,
				KEY_U,
				KEY_V,
				KEY_W,
				KEY_X,
				KEY_Y,
				KEY_Z,
				
				KEY_LEFT,
				KEY_UP,
				KEY_RIGHT,
				KEY_DOWN,
				
				KEY_0,
				KEY_1,
				KEY_2,
				KEY_3,
				KEY_4,
				KEY_5,
				KEY_6,
				KEY_7,
				KEY_8,
				KEY_9,

				KEY_SPACE,
				KEY_SHIFT,
				KEY_CAPSLOCK,
				KEY_CTRL,
				KEY_TAB,
				KEY_ENTER,
				KEY_ESCAPE,

				KEYBOARD_ENUM_MAX_VALUE,
			};

			static enum Mouse
			{
				MS_LEFTBUTTON = 1,
				MS_MIDDLEBUTTON,
				MS_RIGHTBUTTON,
				
				MOUSE_ENUM_MAX_VALUE,
			};

		public:
			
			/**
			 * Get the state of the given key.
			 * @return True if the given key is pressed, else return false.
			 */
			bool isKeyDown(Keyboard _key) const;
			
			/**
			 * Get the state of the given key.
			 * @return True if the given key is not pressed, else return false.
			 */
			bool isKeyUp(Keyboard _key) const;

			/**
			 * Register the given KeyboardInputListener.
			 * @param _keyboard Listener to register.
			 */
			void registerKeyboardInputListener(KeyboardInputListener* _keyboard);
			
			/**
			 * Unregister the given KeyboardInputListener.
			 * @param _keyboard Listener to unregister.
			 */
			void unregisterKeyboardInputListener(KeyboardInputListener* _keyboard);
			
			/**
			 * Get the state of the given mouse button.
			 * @return True if the given mouse button is pushed, else return false.
			 */
			bool isMouseButtonDown(Mouse _but) const;
			
			/**
			 * Get the state of the given mouse button.
			 * @return True if the given mouse button is not pushed, else return false.
			 */
			bool isMouseButtonUp(Mouse _but) const;
			
			/**
			 * Get the actual mouse position in pixel.
			 * (0, 0) correspond to the top left-corner of the screen, while (1, 1) is the bottom-right corner.
			 * @return Vector2 containing the mouse position in pixel.
			 */
			Vector2 getMousePosition() const;
			
			/**
			 * Register the given MouseInputListener.
			 * @param _mouse Listener to register.
			 */
			void registerMouseInputListener(MouseInputListener* _mouse);
			
			/**
			 * Unregister the given MouseInputListener.
			 * @param _mouse Listener to unregister.
			 */
			void unregisterMouseInputListener(MouseInputListener* _mouse);
			
			void _keyDown(WPARAM _key);
			void _keyUp(WPARAM _key);
			void _mouseButtonDown(WPARAM _but, const Vector2& _pos);
			void _mouseButtonUp(WPARAM _but, const Vector2& _pos);
			void _mouseMove(const Vector2& _pos);

		private:
			
			std::vector<bool>					mVectorKeyDown;
			std::vector<bool>					mVectorMouseButtonDown;
			Vector2								mMousePosition;

			std::list<KeyboardInputListener*>	mListKeyboardInputListener;
			std::list<MouseInputListener*>		mListMouseInputListener;

#pragma region Singleton

			private:

				static InputManager* mInstance;
				InputManager(void);

			public:

				static InputManager* getInstance()
				{
					if (mInstance == NULL)
						mInstance = new InputManager();
					return mInstance;
				}

				InputManager(InputManager const&);
				void operator=(InputManager const&);

#pragma endregion
	};

} // namespace FEngine

#endif
